#-------------------------------------------------------------------------------
# Copyright (c) 2012 Huseyin BIYIK.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the GNU Public License v3.0
# which accompanies this distribution, and is available at
# http://www.gnu.org/licenses/gpl.html
# 
# Contributors:
#     Huseyin BIYIK - initial API and implementation
#-------------------------------------------------------------------------------


# TODO LIST:

# 1. implement crc checks for basic flow control
# 2. implement sequence for each datagram for basic flow control
# 3. implement queue ordering and retransmissiom mechanism for basic flow control


import Queue, socket, asyncore
from defs import udp_packet_size, logger

def start():
	asyncore.loop()

class server(asyncore.dispatcher):
	def __init__(self, laddr, lport,on_packet):
		
		asyncore.dispatcher.__init__(self)
		self.lport = lport
		self.laddr = laddr
		self.seq=0
		self.on_packet = on_packet
		self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
		logger.info("Listening on : %s:%s", self.laddr, self.lport)
		try:
			self.bind((self.laddr, self.lport))
			self.laddr, self.lport = self.getsockname()
		except socket.error:
			logger.error("Socket can not bind to adress: %s:%s. Closing interface", self.laddr, self.lport)
		logger.info("Network server has been initialized")

	def handle_close(self):
		logger.info("Closing server")
		self.close()
		return True
	
	def handle_read(self):
		try:
			data,addr=self.recvfrom(udp_packet_size)
			self.on_packet(data,addr)
		except socket.error, e:
			logger.error("Socket errror on receiving : %s", e)
			return (None, None)


class client(asyncore.dispatcher):
	def __init__(self):
		asyncore.dispatcher.__init__(self)
		self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
		self.q=Queue.Queue()
		logger.info("Network client has been initialized")

	
	def sendit(self, data, raddr, rport):
		self.q.put((data, raddr, rport),False)
	
	def handle_write(self):
		try:
			data, raddr, rport=self.q.get(True,0)
		except Queue.Empty:
			return
		try:
			self.sendto(data, (raddr, rport))
			return True
		except socket.error, e:
			logger.error("Socket error on sending : %s" , e)
			return False

	def handle_close(self):
		logger.info("Closing client")
		self.close()
		return True
